<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vue3响应式复习</title>
    <style>
       body{background-color:#1e293b;color: #eeeeee;zoom:1.5;font-size: 16px; overflow-x: hidden;}
       p{font-family: '楷体'; padding-bottom: 0.625rem; }
       a{color: inherit;float: right; text-decoration: none;}
       a:hover{ text-decoration: underline;}
       a:active{ color: #ccc; }
       div{ display:flex; gap:0.1rem; align-items: center; }
       select,input{ height:35px; box-sizing: border-box; }
       select{ width: 40px; }
       option{ font-size: 1.5rem; }
    </style>
</head>
<body>
  <p>
    <a href="javascript:void(0)" onclick="down_file()">下载源码</a>
    路漫漫其修远兮,<br/>
    吾将上下而求索。
  </p>

  <div>
    <form>
     <input type="number" value="1" name="input1" oninput="compute()"> 
     <select onchange="update_config(value)">
        <option value="+">+</option>
        <option value="-">-</option>
        <option value="*">*</option>
        <option value="/">/</option>
        <option value="%">%</option>
     </select>
     <input type="number" value="1" name="input2" oninput="compute()"> =
     <span id="computer_result"></span>
    </form>
  </div>
  
</body>
<script>
  //>>>>>>>>>>>>>>>>>开发视角>>>>>>>>>>>>>>>>>
  const isObject = (obj) => {
     return typeof obj === 'object'
  }

  const e_stack = new WeakMap();
  let activeEffect = null;


  //在effect中保存了即将注册的副作用函数,并且进行了调用,所以才可以将属性和副作用函数进行关联,即依赖收集,不过我认为这个方案问题还是很大...
  const track = (target,key) => {
      if(!activeEffect) return;

      let depMap = e_stack.get(target);

      if(!depMap){
        depMap = new Map();
        e_stack.set(target,depMap)
      }


      let depSet = depMap.get(key);
      if(!depSet){
        depSet = new Set();
        depMap.set(key,depSet);
      }

      depSet.add(activeEffect);
  }
   

  const trigger = (target,key) => {
        let depMap = e_stack.get(target);
        if(!depMap) return;
        
        let depSet = depMap.get(key)

        //第一次打印这里正常
        console.log(e_stack,depMap,depSet);
        if(depSet) depSet.forEach( fn=> fn() )
  }


  const reactive = (obj) => {
      return new Proxy(obj,{
          get(target,key){
             track(target,key);
             return Reflect.get(...arguments)
          },

          //这里需要去改变值,并且触发对应副作用函数
          set(target,key,value){
             Reflect.set(...arguments);
             trigger(target,key);
          }
      })
  }

  const ref = (data) => {
      if(isObject(data)){
        return reactive(data);
      }
       
      return reactive({value:data})
  }
  

  //注册副作用函数
  function effect(fn){
    if(typeof fn !== 'function') return;
    activeEffect = fn;
    fn()                //我觉得vue应该不是这么进行依赖收集的,因为这样太不智能了
    activeEffect = null;
  }


  //>>>>>>>>>>>>>>>>>用户视角(想象一下,你正在使用VUE)>>>>>>>>>>>>>>>>>





  //计算方法 (因为我要测试对象是否也是响应)
  const config = ref({
      method: '+'
  })

  //计算结果
  const result = ref(2);


  
  //更新计算结果
  const updateDom = () => {
     console.log('updateDom');
     computer_result.innerHTML = result.value;
  }
  effect(updateDom)


  //修改计算符号 (副作用:compute)
  const update_config = (method) => {
      config.method = method;
  }


  //开始计算 (副作用:effectFn)
  const inputList = document.getElementsByTagName('input');
  const compute = () => {
      console.log('compute');
      let value1 = inputList['input1'].value;
      let value2 = inputList['input2'].value; 
      let v_result = eval(value1 + config.method + value2);  

      activeEffect = null;
      result.value = (v_result%1 === 0) ? v_result : v_result.toFixed(2);
  }
  effect(compute)


//问题出在: value 收集了两个副作用。。。导致循环引用



  //变量操作
  // console.log('\n\n变量操作>>>>>>');
  // const count = ref(1);
  // console.log(count.value);

  // count.value = 2;
  // console.log(count.value)

  // const isLoading = ref(false);
  // console.log(isLoading.value)

  // isLoading.value = !isLoading.value;
  // console.log(isLoading.value)
  






  //下载源码
  let vue_file = null;
  const down_file = () => {
    if(vue_file === null) vue_file = new Blob([document.documentElement.outerHTML]);
    const objectURLS = URL.createObjectURL(vue_file); 
    const aTags = document.createElement('a');
    aTags.href = objectURLS;
    aTags.download = `vue3响应式原理_简单计算器.html`
    aTags.click()
    URL.revokeObjectURL(objectURLS);
  }
</script>    
</html>